<script lang='ts' setup >
import { CanvasLabel, deepCopy, type LabelType, type CanvasLabelListItem, type CanvasLabelOpType } from 'clabel'
import { nextTick, onMounted, ref } from 'vue';
import { ArrowRightBold, Delete, ArrowLeftBold, Hide,Camera, Search, View, Rank, Aim, ZoomOut, ZoomIn, Top, Bottom, Back, Right, Position, Crop } from '@element-plus/icons-vue'

const selectImgId = ref(-1)
const useLabelTypeList = ref<number[]>([])
let backData = {
    mx: 0,
    my: 0,
    zoom: 1
}
let oldBackData = {
    mx: 0,
    my: 0,
    zoom: 1
}
/**
 * 是否开启 切换图片 缩放比例 保持
 */
const useSaveSacle = ref(false)

const useMode = ref<CanvasLabelOpType>('none')
function getUseModeColor(type: CanvasLabelOpType) {
    return useMode.value == type ? 'grey' : 'black'
}
function getUseModeMapping() {
    let mapping = new Map(Object.entries({
        box: '方框',
        polygon: '多边形'
    }))
    return mapping.get(useMode.value)
}
const imageList = ref<HTMLElement>()
let label: CanvasLabel | null = null
const labelList = ref<CanvasLabelListItem[]>([])
type CollectionImage = {
    name?: string,
    id: number,
    url: string,
    labels: CanvasLabelListItem[]
}
type Collection = {
    name?: string
    iTime?: string
    status?: string
    createBy?: number
    images: CollectionImage[],
    labelTypeList: LabelType[]
}
const labelInfo = ref({
    x: 0,
    y: 0,
    cx: 0,
    cy: 0
})
const collection = ref<Collection>({
    images: [
        {
            id: 1,
            url: '/src/assets/test.jpg',
            labels: [
                {
                    id: 1,
                    labelTypeIds: [1],
                    type: "box",
                    data: [20, 20, 100, 100]
                }
            ]
        },{
            id: 99,
            url: '/src/assets/test.jpg',
            labels: [
                {
                    id: 1,
                    labelTypeIds: [1],
                    type: "box",
                    data: [20, 20, 100, 100]
                }
            ]
        }, {
            id: 2,
            url: '/src/assets/test1.jpg',
            labels: []
        }, {
            id: 3,
            url: '/src/assets/R-C.jpg',
            labels: []
        }, {
            id: 11,
            url: '/src/assets/test.jpg',
            labels: []
        }, {
            id: 21,
            url: '/src/assets/test1.jpg',
            labels: []
        }, {
            id: 31,
            url: '/src/assets/R-C.jpg',
            labels: []
        }, {
            id: 12,
            url: '/src/assets/test.jpg',
            labels: []
        }, {
            id: 22,
            url: '/src/assets/test1.jpg',
            labels: []
        }, {
            id: 32,
            url: '/src/assets/R-C.jpg',
            labels: []
        }, {
            id: 13,
            url: '/src/assets/test.jpg',
            labels: []
        }, {
            id: 23,
            url: '/src/assets/test1.jpg',
            labels: []
        }, {
            id: 33,
            url: '/src/assets/R-C.jpg',
            labels: []
        }
    ],
    labelTypeList: [
        {
            name: '头盔',
            id: 1,
            strokeWidth: 2,
            strokeStyle: 'yellow',
            fillStyle: '#0f04',
            fontFillStyle: 'yellow',
            font: "15px '微软雅黑'"
        }, {
            name: '安全带545454',
            id: 2,
            strokeWidth: 2,
            strokeStyle: 'blue',
            fillStyle: '#0f04',
            fontFillStyle: 'yellow',
            font: "15px '微软雅黑'"
        },
        {
            name: '烟雾',
            id: 4,
            strokeWidth: 4,
            strokeStyle: 'blue',
            fillStyle: '#9364',
            fontFillStyle: 'pink',
            font: "25px '微软雅黑'"
        },
        {
            name: '车辆',
            id: 5,
            strokeWidth: 5,
            strokeStyle: 'blue',
            fillStyle: '#0f04',
            fontFillStyle: 'green',
            font: "15px '微软雅黑'"
        },
        {
            name: '火焰',
            id: 3,
            strokeWidth: 3,
            strokeStyle: 'skyblue',
            fillStyle: '#0f04',
            fontFillStyle: 'yellow',
            font: "15px '微软雅黑'"
        }
    ]
})
// 选择标签
const selectLabelIdList = ref<number[]>([])
const imageSlace = ref(0)
onMounted(() => {
    addEventListener('keyup', changeImage)
    function changeImage(e: KeyboardEvent) {
        if (e.key === 'w'|| e.key ==='W') {
            let index = getImageIndex(selectImgId.value)
            index = index - 1
            if (index < 0) {
                index = 0
            }
            selectImage(collection.value.images[index])
        }
        else if (e.key === 's'|| e.key ==='s') {

            let index = getImageIndex(selectImgId.value)
            index = index + 1
            if (index > collection.value.images.length - 1) {
                index = collection.value.images.length - 1
            }
            selectImage(collection.value.images[index])
        }else if(e.key === 'b'|| e.key ==='B'){
            useSaveSacle.value = !useSaveSacle.value
        }else if(e.key==="Delete"){
            label?.delLabel(selectLabelIdList.value)
        }
    }
    label = new CanvasLabel('#canvas_m', true)
    label.setSetting({
        labelTypeList: collection.value.labelTypeList,
        background: "rgb(31,31,31)"
    })
    label.onEvent((e) => {
        if (e?.type == "drawEnd") {
            console.log("重绘")
            labelList.value = e.data
            selectLabelIdList.value = label?.getSelectLabelsIds() || []
            useLabelTypeList.value = label?.getUseLabelType() || []
        } else if (e?.type == 'hover') {
            labelInfo.value = e.data
        } else if (e?.type == "checkType") {
            useMode.value = e.data
        } else if (e?.type == 'checkLabelType') {
            useLabelTypeList.value = e.data
        } else if (e?.type == 'scale') {
            backData = e.data
            imageSlace.value = e.data.zoom
            console.log(e.data);
        } else if (e?.type == 'select') {
            selectLabelIdList.value = e.data
        } else if (e?.type == 'translate') {
            backData = e.data
            console.log(e.data);

        }
    })
    collection.value.images[0]
    selectImage(collection.value.images[0])
})

function changeUseLabel() {
    label?.useLabelType(useLabelTypeList.value)
}

const onWheel = (e: WheelEvent) => {
    e.preventDefault()
    if (!imageList.value) {
        return
    }
    let y = 0
    if (e.deltaY > 0) {
        y = 50
    } else {
        y = -50
    }
    imageList.value.scrollLeft = imageList.value.scrollLeft + y
}
const imageListScroll = (e: MouseEvent, val: 'r' | 'l') => {

    if (!imageList.value) {
        return
    }
    if (val == "r")
        imageList.value.scrollLeft = imageList.value.scrollLeft + 200
    else
        imageList.value.scrollLeft = imageList.value.scrollLeft - 200
}

function delLabel(id: number) {
    label?.delLabel(id)
    labelList.value = label?.getLabelList() || []
}
/**
 * 
 * @param i 正在选择的图片
 */
function selectImage(i: CollectionImage) {

    collection.value.images.forEach((d) => {
        // 如果图片列表的 图片是之前选中的图片 就保存之前的标签数据
        if (d.id == selectImgId.value) {
            d.labels = deepCopy(label?.getLabelList()) || []
        }

    })
    // 如果图片是现在选中的 就绘制到 canvas上
    label?.drawImage(i.url).then(() => {
        useMode.value = label?.getOpType() || 'none'
        if (useSaveSacle.value) {
            label?.scale(oldBackData.zoom - backData.zoom)
            label?.translate(oldBackData.mx - backData.mx, oldBackData.my - backData.my)
        }
    })
    labelList.value = JSON.parse(JSON.stringify(i.labels))
    label?.setLabelList(labelList.value)
    selectImgId.value = i.id
    nextTick(() => {
        imageList.value?.scrollTo({
            "left": getImageIndex(i.id) * 200 - 400
        })
    })
    label?.checkOpType('none')
    oldBackData = backData
}
function getImageIndex(id: number) {
    let images = collection.value.images
    let index = 0
    for (let img of images) {
        if (id == img.id) {
            return index
        }
        index++
    }
    return -1
}


function getImageLabel(id: number) {
    const img = collection.value.images[getImageIndex(selectImgId.value)]
    for (let label of img.labels) {
        if (label.id === id) {
            return label
        }
    }
    return {
        type: ""
    }
}
function getImageLabels() {
    const img = collection.value.images[getImageIndex(selectImgId.value)]
    return img.labels
}
function getImageLabelIndex(lid: number) {
    const labels = getImageLabels()
    let i = 0
    for (let label of labels) {
        if (label.id === lid) {
            console.log(label.id, lid);
            return i
        }
        i++
    }
}
/**
 * 选择标签
 */
function selectLabel(e: MouseEvent, l: CanvasLabelListItem, index?: number) {
    label?.checkOpType('select')
    const i = selectLabelIdList.value.indexOf(l.id)
    if (e.ctrlKey) {
        if (i >= 0) {
            selectLabelIdList.value.splice(i, 1)
            label?.selectLabels([...selectLabelIdList.value])
        } else {
            label?.selectLabels([...selectLabelIdList.value, l.id])
        }
    } else if (e.shiftKey) {
        if (selectLabelIdList.value[0] !== undefined) {
            // 获取标签的index 
            // 初始index 以及最后点击的
            const fli = getImageLabelIndex(selectLabelIdList.value[0])
            selectLabelIdList.value = []

        } else {
            selectLabelIdList.value = []
            selectLabelIdList.value.push(l.id)
        }
    } else {
        label?.selectLabels([l.id])
    }
}
function getSelectLabelStyle(id: number) {
    return selectLabelIdList.value.indexOf(id) >= 0 ? "label-select-ing" : ""
}
</script>
<template>
    <div id="labelPageRoot">
        <div class="label-tool-list">
            <div class="tool-title-top">工具</div>
            <div class="tool-content">

                <el-tooltip class="box-item" effect="dark" content="查看( a | A )" placement="right">
                    <el-button size="large" @click="label?.checkOpType('none')" :color="getUseModeColor('none')">
                        <el-icon :size="20">
                            <Search />
                        </el-icon>
                    </el-button>
                </el-tooltip>
                <el-tooltip class="box-item" effect="dark" content="移动( shift )" placement="right">
                    <el-button size="large" @click="label?.checkOpType('move')" :color="getUseModeColor('move')">
                        <el-icon :size="20">
                            <Rank />
                        </el-icon>
                    </el-button>
                </el-tooltip>
                <el-tooltip class="box-item" effect="dark" content="放大( ctrl + 滚轮↑ )" placement="right">
                    <el-button size="large" @click="label?.scale(.1)" color="black">
                        <el-icon :size="20">
                            <ZoomIn />
                        </el-icon>
                    </el-button>
                </el-tooltip>
                <el-tooltip class="box-item" effect="dark" content="缩小( ctrl + 滚轮↓ )" placement="right">
                    <el-button size="large" @click="label?.scale(-.1)" color="black">
                        <el-icon :size="20">
                            <ZoomOut />
                        </el-icon>
                    </el-button>
                </el-tooltip>
                <el-tooltip class="box-item" effect="dark" content="上移( 滚轮↓ )" placement="right">
                    <el-button size="large" @click="label?.translate(0, -100)" color="black"><el-icon :size="20">
                            <Top />
                        </el-icon>
                    </el-button>
                </el-tooltip>
                <el-tooltip class="box-item" effect="dark" content="下移( 滚轮↑ )" placement="right">
                    <el-button size="large" @click="label?.translate(0, 100)" color="black"><el-icon :size="20">
                            <bottom />
                        </el-icon>
                    </el-button>
                </el-tooltip>
                <el-tooltip class="box-item" effect="dark" content="左移( alt + 滚轮↓ )" placement="right">
                    <el-button size="large" @click="label?.translate(-100, 0)" color="black"><el-icon :size="20">
                            <Back />
                        </el-icon>
                    </el-button>
                </el-tooltip>
                <el-tooltip class="box-item" effect="dark" content="右移( alt + 滚轮↑ )" placement="right">
                    <el-button size="large" @click="label?.translate(100, 0)" color="black"><el-icon :size="20">
                            <Right />
                        </el-icon>
                    </el-button>
                </el-tooltip>
                <el-tooltip class="box-item" effect="dark" content="方框( f | F )" placement="right">
                    <el-button size="large" @click="label?.checkOpType('box')" :color="getUseModeColor('box')"
                        native-type="div"><el-icon :size="20">
                            <Crop />
                        </el-icon>
                    </el-button>
                </el-tooltip>
                <el-tooltip class="box-item" effect="dark" content="多边形( d | D )" placement="right">
                    <el-button size="large" @click="label?.checkOpType('polygon')"
                        :color="getUseModeColor('polygon')"><el-icon :size="20">
                            <Position />
                        </el-icon>
                    </el-button>
                </el-tooltip>
                <el-tooltip class="box-item" effect="dark" content="选择模式( q | Q )" placement="right">
                    <el-button size="large" @click="label?.checkOpType('select')" :color="getUseModeColor('select')">
                        <el-icon :size="20">
                            <Aim />
                        </el-icon>
                    </el-button>
                </el-tooltip>
                <el-tooltip class="box-item" effect="dark" content="保持缩放比例( b | B )" placement="right">
                    <el-button size="large" @click="useSaveSacle = !useSaveSacle" :color="useSaveSacle?'grey':'black'">
                        <el-icon :size="20">
                            <Camera />
                        </el-icon>
                    </el-button>
                </el-tooltip>
            </div>
        </div>
        <div class="label-main">
            <div class="canvas-main" id="canvas_m">

            </div>
            <div class="btn">
                <div class="image-list" id="test" @wheel="onWheel" ref="imageList">
                    <span class="img-ctx" :class="selectImgId == item.id ? 'img-selecting' : ''"
                        v-for="item in collection.images" :key="item.id">
                        <img @click="selectImage(item)" :src="item.url" alt="">
                    </span>
                    <el-button @click="imageListScroll($event, 'l')" color="transparent" size="large" class="btnprev"
                        :icon="ArrowLeftBold" circle />
                    <el-button @click="imageListScroll($event, 'r')" color="transparent" size="large" class="btnnext"
                        :icon="ArrowRightBold" circle />
                </div>
            </div>
            <div class="canvas-label-info">
                <div class="title">
                    <span style="margin-right: 10px;">当前选择: {{ getUseModeMapping() }}</span>
                    <span style="margin-right: 10px;">图片总数: {{ getImageIndex(selectImgId) + 1 }}/{{ collection.images.length
                    }}</span>
                    <span style="margin-right: 10px;">缩放倍率:{{ imageSlace.toFixed(2) }}</span>
                    <span style="margin-right: 10px;">画布坐标 x: {{ labelInfo.x.toFixed(2) }} y: {{ labelInfo.y.toFixed(2)
                    }}</span>
                    <span style="margin-right: 10px;">图片坐标 x: {{ labelInfo.cx.toFixed(2) }} y: {{ labelInfo.cy.toFixed(2)
                    }}</span>
                </div>
            </div>
        </div>
        <div class="label-list">
            <div class="label-types">
                <el-tabs type="border-card" class="scroll">
                    <el-tab-pane label="类别">
                        <div class="content">
                            <div v-for="item in collection.labelTypeList" :key="item.id">
                                <el-checkbox style="width: 70%; margin-left: 5%;" v-model="useLabelTypeList"
                                    @change="changeUseLabel" :label="item.id" size="large">
                                    <span>{{ item.name }}</span>
                                </el-checkbox>
                                <el-switch style="margin-bottom: 5px;" size="small"
                                    :modelValue="(!label?.labelTypeIsHidden(item.id) as boolean)" :active-action-icon="View"
                                    :inactive-action-icon="Hide" @change="label?.checkHiddenLabelType(item.id)" />
                            </div>
                        </div>
                    </el-tab-pane>
                    <el-tab-pane label="标签">
                        <div style="margin-left: 15px;" class="label-item" v-for="id in selectLabelIdList" :key="id">
                            <!--  -->
                            <div style="color: aqua;">
                                box{{ getImageLabel(id)?.type + id }}
                            </div>
                            <div style="display: flex; flex-wrap: wrap;">
                                <div style="width: 33.3%; height: auto;" v-for="item in collection.labelTypeList"
                                    :key="item.id">
                                    <el-checkbox :label="item.id" @change="label?.checkLabelLabelType(id, item.id)"
                                        :modelValue="label?.labelHasLabelType(id, item.id)">
                                        {{ item.name }}
                                    </el-checkbox>
                                </div>
                            </div>
                        </div>
                    </el-tab-pane>
                </el-tabs>
            </div>
            <div class="label-items">
                <h3 class="itemBox">标注列表
                    <div class="btnicon">
                        <el-icon color="red" @click="label?.delLabel(selectLabelIdList)">
                            <Delete />
                        </el-icon>
                        <el-icon color="aqua" @click="selectLabelIdList.forEach(id=>label?.checkHiddenLabel(id)) ">
                            <View />
                        </el-icon>
                    </div>
                </h3>
                <div class="content scroll">

                    <div @click="selectLabel($event, l, index)" :class="getSelectLabelStyle(l.id)"
                        style="margin-left: 15px;" class="label-item" v-for="(l, index) in labelList" :key="l.id">
                        <span>{{ l.type + l.id }}</span>
                        <div class="btnicon">
                            <el-icon color="red" @click="delLabel(l.id)">
                                <Delete />
                            </el-icon>
                            <el-icon @click="label?.checkHiddenLabel(l.id)" color="aqua">
                                <View />
                            </el-icon>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</template>
<style lang="less" scoped>
@import "../../../assets/g.less";

@back-color: black;
@border-color: rgb(46, 46, 46);

.el-button:focus-visible {
    outline: none;
}

#labelPageRoot {
    width: 100vw;
    height: 100vh;
    display: flex;
    --tool-width: 50px;
    --libel-list: 250px;

    .label-tool-list {
        width: var(--tool-width);
        height: 100%;
        box-sizing: border-box;
        background-color: @back-color;
        border-right: 1px @border-color solid;
    }

    .label-main {
        width: calc(100% - var(--tool-width) - var(--libel-list));
    }

    .label-list {
        width: var(--libel-list);
        box-sizing: border-box;
        border-left: 1px @border-color solid;
    }
}

// ============================ 工具
.label-tool-list {
    .tool-title-top {
        font-size: 16px;
        text-align: center;
        margin: 25px 0;
        color: #fff;
    }

    .tool-content {
        width: 100%;
        height: 50%;
        display: flex;
        flex-direction: column;

        .el-button+.el-button {
            margin-left: 0;
        }
    }
}

.label-main {
    height: 100%;
    background-color: rgb(31, 31, 31);
    @labinfo-height: 30px;
    --btn-height: 140px;

    .canvas-main {
        height: calc(100% - var(--btn-height) - @labinfo-height);
        background-color: #D3DCE6;
    }

    .btn {
        position: relative;
        height: var(--btn-height);
    }

    .canvas-label-info {
        height: @labinfo-height;
        background: @back-color;
        color: #fff;

        .title {
            line-height: 30px;
            font-size: 12px;
            float: right;
            margin-right: 10px;
        }
    }

    .btn {
        position: relative;
        width: 100%;

        .image-list {
            height: 100%;
            width: 100%;
            background-color: #fff;
            overflow: hidden;
            white-space: nowrap;

            span {
                display: inline-block;
                width: 200px;
                height: 100%;
            }

            .btnprev {
                position: absolute;
                top: calc(50% - 20px);
                left: 0.5%;
            }

            .btnnext {
                position: absolute;
                top: calc(50% - 20px);
                right: 0.5%
            }

        }

        .img-selecting {
            outline-offset: -3px;
            outline-width: 3px;
            outline-color: yellow;
            outline-style: solid;
        }

        .img-ctx {
            img {
                width: 100%;
                height: 100%;
            }
        }
    }

}

.label-list {
    height: 100%;
    background-color: @back-color;

    .label-types {
        height: 60%;
        box-sizing: border-box;

        & ::v-deep .el-tabs__nav-scroll {
            background-color: black;
        }

        & ::v-deep .el-tabs--border-card {
            border: none;
            background-color: transparent;
        }

        & ::v-deep .el-tabs--border-card>.el-tabs__header .el-tabs__item.is-active {
            color: var(--el-color-primary);
            background-color: #252121;
            border: none;
            outline: none;
        }

        & ::v-deep .el-tabs--border-card>.el-tabs__content {
            height: calc(100% - 40px);
            box-sizing: border-box;
            .scroll()
        }

        .el-tabs {
            height: 100%;
        }

        .title {
            color: #fff;
        }

        ::v-deep .el-checkbox__label {
            width: 60px;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
        }

    }

    .label-items {
        border-top: 1px solid @border-color;
        user-select: none;
        height: 36.5%;
        box-sizing: border-box;
        color: #fff;

        .itemBox {
            margin: 5px 0 0 15px;
            padding: 0 10px;
            display: flex;
            justify-content: space-between;
            align-items: center;
            width: 80%;
        }

        .label-item {
            overflow: hidden;
            padding: 0 10px;
            display: flex;
            justify-content: space-between;
            align-items: center;
            width: 80%;
            height: 40px;
        }
    }

    .label-select-ing {
        background: @border-color;
        border-radius: 5px;
    }

    .content {
        height: 100%;
        width: 100%;

    }
}</style>